#include "Database.h"

Database::Database(std::string file_name)
{
    std::ifstream infile;
    infile.open(file_name + ".sdb", std::ios::in);

    this->name = file_name;
    infile >> table_count;

    for (int i = 0; i < table_count; i++) { // input n tables
        Table tb;
        infile >> tb.name >> tb.field_count >> tb.record_count;
        
        std::string field_type, field_name;

        for (int j = 0; j < tb.field_count; j++) { // input n fields for this table
            infile >> field_type >> field_name;
            Field fd;

            fd.name = field_name;

            if (field_type == "int") fd.type = 0;
            else if (field_type == "float") fd.type = 1;
            else fd.type = 2;

            std::string val;
            for (int k = 0; k < tb.record_count; k++) {
                infile >> val;
                fd.add_item(val);
            }

            tb.fields.push_back(fd);
        }

        this->tables.push_back(tb);
    }

    infile.close();
}

void Database::write_back() {
    std::ofstream output;
    output.open(this->name + ".sdb", std::ios::out | std::ios::trunc);

    output << table_count << std::endl << std::endl;

    // tables
    for (auto tb : this->tables) {

        output << tb.name << " ";
        output << tb.field_count << " ";
        output << tb.record_count << std::endl;

        // fields and records for this table
        for (auto fd : tb.fields) {
            if (fd.type == 0) output << "int ";
            else if (fd.type == 1) output << "float ";
            else output << "string ";

            output << fd.name << " ";

            // records
            if (fd.type == 0) {
                for (auto i : fd.records_int)
                    output << i << " ";
            } else if (fd.type == 1) {
                for (auto i : fd.records_float)
                    output << i << " ";
            } else {
                for (auto i : fd.records_string)
                    output << i << " ";
            }

            output << std::endl;
        }
        output << std::endl;
    }

    output.close();
}

void Database::info() {
    std::cout << "Database: \"" << this->name << "\":" << std::endl;
    std::cout << "Total " << table_count << " data tables:" << std::endl;
    for (auto i : this->tables) {
        std::cout << "    - " << i.name << std::endl;
    }
}

void Database::table_info(std::string table_name) {
    for (auto i : this->tables) {
        if (i.name == table_name) {
            i.info();
            return;
        }
    }
    std::cout << "ERROR: no table named \"" << table_name << "\" found." << std::endl;
}

void Database::create_table(std::string table_name, std::string fields_set) {
    // fields_set = "string id, string name, float math, float cs, float english"
    Table tb(table_name, fields_set);

    this->tables.push_back(tb);
    this->table_count++;
}

void Database::drop_table(std::string table_name) {
    for (auto it = this->tables.begin(); it != this->tables.end(); it++) {
        if (it->name == table_name) {
            this->tables.erase(it);
            this->table_count--;
            return;
        }
    }
    std::cout << "ERROR: no table named \"" << table_name << "\" found." << std::endl;
}

void Database::insert_record(std::string table_name, std::string fields) {
    // table_name = "user"
    // fields = "id=’210001’ , name=’liming’ , math=90,  cs=92.5, english=87"
    for (auto it = this->tables.begin(); it != this->tables.end(); it++) {
        if (it->name == table_name) {
            it->add_record(fields);
            return;
        }
    }
    std::cout << "ERROR: no table named \"" << table_name << "\" found." << std::endl;
}

void Database::delete_record(std::string table_name, std::string filter) {
    for (auto it = this->tables.begin(); it != this->tables.end(); it++) {
        if (it->name == table_name) {
            it->delete_record(filter);
            return;
        }
    }
    std::cout << "ERROR: no table named \"" << table_name << "\" found." << std::endl;
}

void Database::select_record(std::string table_name, std::string show_fields, std::string filters, std::string order) {
    for (auto it = this->tables.begin(); it != this->tables.end(); it++) {
        if (it->name == table_name) {
            it->select(show_fields, filters, order);
            return;
        }
    }
    std::cout << "ERROR: no table named \"" << table_name << "\" found." << std::endl;
}
